package Timer;
use Util;
use strict;

my @timers; # timers scheduled queue
my $timer_id_cnt = 0;

# Schedule an execution of a given subroutine with given arguments
# $_[0] -- subrouting reference
# $_[1] -- timeout given in seconds
# $_[2] -- if set to 1, repeatedly run the subroutine every given timeout
# $_[3..@#_] - all the arguments to the subroutine
# returns timer id which can be used by del_timer subroutine
#
# Reapeatedly run a check_smth("dupa", 25) subroutine every 10 seconds
# Example: Timer::set(\&check_smth, 10, 1, "dupa", 25);
sub set
{
        my $subroutine = shift;
        my $timeout    = shift;
        my $continous  = shift;

        my $run_time = time() + $timeout;

        my $timer_id = ++$timer_id_cnt;

        my $i = @timers;
        while ($i--) {
                if (@{$timers[$i]}[0] < $run_time) {
                        Util::insert_after(@timers, $i, [$run_time, $timer_id, $timeout, $subroutine, $continous, @_]);
                }
        }
        unshift(@timers, [$run_time, $timer_id, $timeout, $subroutine, $continous, @_]);

        return $timer_id;
}

# Simple timer deleting function
# $_[0] -- timer id
# returns 0 on success and 1 on failure(timer not found)
sub del
{
        my $timer_id = $_[0];
        my $i        = @timers;
        while ($i--) {
                if (@{$timers[$i]}[1] == $timer_id) {    # Id matched
                        splice(@timers, $i);
                        return 0;
                }
        }
        return 1;
}


# Check timers for timeout and run the callback functions.
sub handle_timers
{
        while (@timers and @{$timers[0]}[0] <= time()) {    # Iterate through late timers
                my @timer = @{shift(@timers)};
                $timer[3]->(@timer[5 .. $#timer]);          # Get the subroutine arguments and execute the subroutine

                if ($timer[4] > 0) {                        # Reschedule if desired
                        $timer[0] = time() + $timer[2];
                        my $i = @timers;
                        while ($i--) {
                                if (@{$timers[$i]}[0] < $timer[0]) {    # Insert into the correct place to the queue
                                        Util::insert_after(@timers, $i, [@timer]);
                                        last;
                                }
                        }
                        if ($i == -1) {                                 # Put at the beginning
                                unshift(@timers, [@timer]);
                        }
                }
        }
}
1;